package org.wk.core.common.http;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;


/**
* @ClassName	: LBSRequestBase
* @Package		：com.lbs.core.http
* @Author mars mars@labsport.cn
* @Create Time	：2016年8月27日 下午2:06:34
* @Description	: 
*/ 
public abstract class LBSRequestBase implements LBSRequest,HttpRequestRetryHandler{
	public CloseableHttpClient httpClient = null;
	public CloseableHttpClient getHttpClient(String url) {
		// TODO Auto-generated method stub
		String hostname = url.split("/")[2];
		int port = 80;
		if (hostname.contains(":")) {
			String[] arr = hostname.split(":");
			hostname = arr[0];
			port = Integer.parseInt(arr[1]);
		}
		if (httpClient == null) {
			httpClient = getHttpClient(hostname, port);
		}
		return httpClient;
	}
	@Override
	public String postContent(String url) {
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		Map<String, String> postExc = postExc(url, httppost);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	public String postBody(String url,String content){
		HttpPost httppost = new HttpPost(url);
		StringEntity entity = null;
		entity = new StringEntity(content, "UTF-8");
		httppost.setEntity(entity);
		config(httppost);
		Map<String, String> postExc = postExc(url, httppost);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	@Override
	public Map<String, String> post(String url) {
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		return postExc(url, httppost);
	}
	@Override
	public String postContent(String url, Map<String, Object> params) {
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		setPostParams(httppost, params);
		Map<String, String> postExc = postExc(url, httppost);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	
	@Override
	public Map<String, String> post(String url, Map<String, Object> params) {
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		setPostParams(httppost, params);
		return postExc(url, httppost);
	}
	@Override
	public String postRest(String url, Map<String, Object> params){
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		setPostParams(httppost,params);
		Map<String, String> postExc = postExc(url, httppost);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	@Override
	public String getRest(String url){
		HttpGet httpget = new HttpGet(url);
		config(httpget);
		CloseableHttpResponse response = null;
		try {
			response = getHttpClient(url).execute(httpget, HttpClientContext.create());
			HttpEntity entity = response.getEntity();
			String result = EntityUtils.toString(entity, "utf-8");
			EntityUtils.consume(entity);
			return result;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
		
	}
	@Override
	public String putRest(String url, Map<String, Object> params){
		HttpPut httpPut = new HttpPut(url);
		config(httpPut);
		setPostParams(httpPut,params);
		Map<String, String> postExc = postExc(url, httpPut);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	@Override
	public String deleteRest(String url, Map<String, Object> params){
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("X-HTTP-Method-Override", "DELETE");
		this.setHeaders(headers );
		HttpPost httppost = new HttpPost(url);
		config(httppost);
		setPostParams(httppost,params);
		Map<String, String> postExc = postExc(url, httppost);
		return postExc!=null?postExc.get(LBSRequest.ResponseMessage):null;
	}
	
	@Override
	public String get(String url) {
		HttpGet httpget = new HttpGet(url);
		config(httpget);
		CloseableHttpResponse response = null;
		try {
			response = getHttpClient(url).execute(httpget, HttpClientContext.create());
			HttpEntity entity = response.getEntity();
			String result = EntityUtils.toString(entity, "utf-8");
			EntityUtils.consume(entity);
			return result;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	@Override
	public boolean retryRequest(IOException exception,
			int executionCount, HttpContext context) {
		if (executionCount >= 5) {// 如果已经重试了5次，就放弃
			return false;
		}
		if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
			return true;
		}
		if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
			return false;
		}
		if (exception instanceof InterruptedIOException) {// 超时
			return true;
		}
		if (exception instanceof UnknownHostException) {// 目标服务器不可达
			return false;
		}
		if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
			return false;
		}
		if (exception instanceof SSLException) {// SSL握手异常
			return false;
		}
		HttpClientContext clientContext = HttpClientContext.adapt(context);
		HttpRequest request = clientContext.getRequest();
		// 如果请求是幂等的，就再次尝试
		if (!(request instanceof HttpEntityEnclosingRequest)) {
			return true;
		}
		return false;
	}
	
	private Map<String, String> postExc(String url, HttpEntityEnclosingRequestBase httpEntityEnclosingRequestBase) {
		Map<String, String> responseMap = new HashMap<String,String>();
		CloseableHttpResponse response = null;
		try {
			CloseableHttpClient _httpClient = getHttpClient(url);
			response = _httpClient.execute(httpEntityEnclosingRequestBase, HttpClientContext.create());
			Header[] allHeaders = response.getAllHeaders();
			for (Header header : allHeaders) {
				responseMap.put(header.getName(), header.getValue());
			}
			HttpEntity entity = response.getEntity();
			String result = EntityUtils.toString(entity, "utf-8");
			responseMap.put(LBSRequest.ResponseMessage, result);
			EntityUtils.consume(entity);
			return responseMap;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	public void setPostParams(HttpEntityEnclosingRequestBase httpEntityEnclosingRequestBase, Map<String, Object> params) {
		if (params != null && params.size() > 0) {
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			Set<String> keySet = params.keySet();
			for (String key : keySet) {
				nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
			}
			try {
				httpEntityEnclosingRequestBase.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
	}
	public abstract void config(HttpRequestBase httpRequestBase);
	public abstract CloseableHttpClient getHttpClient(String hostname, int port);
}
